package com.zmn.brs.services.impl.event;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.zmn.brs.business.interfaces.rule.AlarmRuleBService;
import com.zmn.brs.common.enums.*;
import com.zmn.brs.model.entity.event.EventBase;
import com.zmn.brs.model.entity.objective.event.ObjectiveEvent;
import com.zmn.brs.model.entity.objective.rule.ObjectiveRule;
import com.zmn.brs.model.entity.rule.AlarmRule;
import com.zmn.brs.model.entity.scene.Scene;
import com.zmn.brs.model.entity.threshold.Threshold;
import com.zmn.brs.model.query.rule.EarlyWarningConfig;
import com.zmn.brs.model.vo.event.ObjEventVO;
import com.zmn.brs.model.vo.rule.objective.ObjectiveRuleVO;
import com.zmn.brs.persistence.interfaces.objective.event.ObjectiveEventDao;
import com.zmn.brs.persistence.interfaces.objective.rule.ObjectiveRuleDao;
import com.zmn.brs.persistence.interfaces.rule.AlarmRuleDao;
import com.zmn.brs.persistence.interfaces.scene.SceneDao;
import com.zmn.brs.persistence.interfaces.threshold.ThresholdDao;
import com.zmn.common.dto2.ResponseDTO;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.number.NumberUtil;
import com.zmn.manager.common.database.annotation.ReadOnlyConnection;
import com.zmn.mcc.dubbo.dto.DubboConsts;
import com.zmn.okr.common.constant.ObjectiveMasterTypeConst;
import com.zmn.okr.common.model.base.PageDRO;
import com.zmn.okr.common.model.dio.objective.ObjectiveDIO;
import com.zmn.okr.common.model.dio.objective.ObjectiveQueryDIO;
import com.zmn.okr.dubbo.interfaces.objective.ObjectiveRemoteService;
import com.zmn.plat.common.dictionary.StatusEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.Reference;
import org.joda.time.DateTime;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

import com.zmn.brs.model.entity.event.Event;
import com.zmn.brs.model.entity.event.EventQuery;
import com.zmn.brs.services.interfaces.event.EventService;
import com.zmn.brs.persistence.interfaces.event.EventDao;

/**
 * 描述: 事件基础接口实现类
 *
 * @author xujie
 * @since  2021-03-17 13:55:07
 **/
@Slf4j
@Service
public class EventServiceImpl implements EventService {

    private static final String TAG = "事件基础服务接口";

    @Resource
    private EventDao eventDao;

    @Resource
    private ObjectiveEventDao objectiveEventDao;

    @Resource
    private AlarmRuleDao alarmRuleDao;

    @Resource
    private ObjectiveRuleDao objectiveRuleDao;

    @Resource
    private ThresholdDao thresholdDao;

    @Resource
    private AlarmRuleBService alarmRuleBService;

    @Resource
    private SceneDao sceneDao;

    @Reference(version = DubboConsts.INTERFACE_VERSION, check = false)
    private ObjectiveRemoteService objectiveRemoteService;

    /**
     * 描述: 根据id查询数据
     *
     * @param eventId id
     * @author xujie
     * @since 2021-03-17 13:55:07
     **/
    @Override
    @ReadOnlyConnection
    public Event findById(Integer eventId) {

        Assert.notNull(eventId, TAG + "参数 eventId 不能为空");
        return eventDao.findById(eventId);
    }

    /**
     * 描述: 根据事件编码查询数据
     *
     * @param eventCode 事件编码
     * @return Event
     * @author xujie
     * @since 2021-04-01
     **/
    @Override
    @ReadOnlyConnection
    public Event findByEventCode(Integer eventCode) {

        Assert.notNull(eventCode, TAG + "参数 eventCode 不能为空");
        return eventDao.findByEventCode(eventCode);
    }

    /**
     * 描述: 根据事件类型查询事件基础数据
     *
     * @param eventType 事件类型：1:登录，2:导出，3:查询
     * @return List<EventBase>
     * @author xujie
     * @since 2021-03-19 10:10:07
     **/
    @Override
    @ReadOnlyConnection
    public List<EventBase> listByEventType(Integer eventType) {

        Assert.notNull(eventType, TAG + "参数 eventType 不能为空");
        return eventDao.listByEventType(eventType);
    }

    /**
     * 描述: 根据事件编码列表查询事件基础数据
     *
     * @param eventCodeList 事件编码列表
     * @return List<EventBase>
     * @author xujie
     * @since 2021-03-18 18:38:07
     **/
    @Override
    @ReadOnlyConnection
    public List<EventBase> listByEventCodeList(List<Integer> eventCodeList) {

        if (eventCodeList == null || eventCodeList.size() == 0) {
            return new ArrayList<>();
        }
        return eventDao.listByEventCodeList(eventCodeList);
    }

    /**
     * 描述: 按条件查询数据 支持分页
     *
     * @param query 查询对象
     * @author xujie
     * @since 2021-03-17 13:55:07
     **/
    @Override
    @ReadOnlyConnection
    public List<Event> listPageByQuery(EventQuery query) {

        Assert.notNull(query, TAG + "参数 query 不能为空");
        query.setTotalCount(eventDao.countByQuery(query));
        return eventDao.listPageByQuery(query);
    }

    /**
     * 描述: 按条件查询数据 不支持分页
     *
     * @param query 查询对象
     * @author xujie
     * @since 2021-03-17 13:55:07
     **/
    @Override
    @ReadOnlyConnection
    public List<Event> listByQuery(EventQuery query) {

        Assert.notNull(query, TAG + "参数 query 不能为空");
        return eventDao.listByQuery(query);
    }

    /**
     * 描述: 按条件查询数据 不支持分页
     *
     * @param query 查询对象
     * @author xujie
     * @since 2021-03-17 13:55:07
     **/
    @Override
    @ReadOnlyConnection
    public Integer countByQuery(EventQuery query) {

        Assert.notNull(query, TAG + "参数 query 不能为空");
        return eventDao.countByQuery(query);
    }

    /**
     * 描述: 根据id修改数据 id为必传
     *
     * @param event 待修改数据
     * @return java.lang.Integer
     * @author xujie
     * @since 2021-03-17 13:55:07
     **/
    @Override
    public Integer updateByKey(Event event) {

        Assert.notNull(event, TAG + "参数 event 不能为空");
        Assert.notNull(event.getEventCode(), TAG + "字段 eventCode 不能为空");
        return eventDao.updateByKey(event);
    }

    /**
     * 描述: 根据id修改数据 id为必传
     *
     * @param event 待修改数据
     * @return java.lang.Integer
     * @author xujie
     * @since  2021-03-17 13:55:07
     **/
    @Override
    @Transactional
    public Integer updateEventByKey(Event event){
        AtomicReference<Integer> flag = new AtomicReference<>(0);
        //获取事件场景
        Scene scene = sceneDao.findById(event.getSceneId());
        //判断是否是绩效经营指标监控，是则执行绩效事件扩展表数据更新插入操作
        if(scene != null && SceneTypeEnum.TARGET.getTypeId().equals(scene.getType())) {
            //查询目标事件
            ObjectiveEvent objectiveEvent = Optional.ofNullable(objectiveEventDao.findByEventId(event.getEventId())).orElse(
                    ObjectiveEvent.builder()
                            .eventId(event.getEventId())
                            .eventCode(event.getEventCode())
                            .subgoalId(event.getRelateId())
                            .updater(event.getUpdater())
                            .creater(event.getUpdater())
                            .createTime(DateUtil.getNow())
                            .updateTime(DateUtil.getNow())
                            .build()
            );
            //设置cube快照ID
            objectiveEvent.setCubeSnapshotId(event.getCubeSnapshotId());
            //判断目标是否未创建，没有则创建
            if (NumberUtil.isNullOrZero(objectiveEvent.getObjEventId())) {
                flag.updateAndGet(v -> v + objectiveEventDao.insert(objectiveEvent));
            } else {
                flag.updateAndGet(v -> v + objectiveEventDao.updateByKey(objectiveEvent));
            }
        }
        Map<String, Object> common = event.getCommon();
        if(common != null && !common.isEmpty()){
            event.setCommon(common);
            alarmRuleBService.upsertEventCommonRule(event);
        }
        //修改事件
        flag.updateAndGet(v -> v + this.updateByKey(event));
        return flag.get();
    }

    /**
     * 描述: 批量修改数据
     * @param eventList 数据集合
     * @return java.lang.Integer 成功个数
     * @author xujie
     * @since  2021-03-17 13:55:07
     */
    @Override
    public Integer updateBatchByKey(List<Event> eventList) {

        if (eventList == null || eventList.size() == 0) {
            return null;
        }
        return eventDao.updateBatchByKey(eventList);
    }

    /**
     * 描述: 新增数据
     *
     * @param event 待新增数据
     * @return java.lang.Integer 主键key
     * @author xujie
     * @since  2021-03-17 13:55:07
     **/
    @Override
    public Integer insert (Event event) {

        Assert.notNull(event, TAG + "参数 event 不能为空");
        return eventDao.insert(event);
    }

    /**
     * 描述: 批量新增数据
     * @param eventList 待新增数据集合
     * @return java.lang.Integer 成功个数
     * @author xujie
     * @since  2021-03-17 13:55:07
     */
    @Override
    public Integer insertBatch(List<Event> eventList) {

        if (eventList == null || eventList.size() == 0) {
            return null;
        }
        return eventDao.insertBatch(eventList);
    }

    /**
     * 描述: 批量新增事件
     * @param objEventVO
     * @return
     */
    @Override
    @Transactional
    public Integer addEvent(ObjEventVO objEventVO){
        Date now = DateUtil.getNow();
        AtomicReference<Integer> flag = new AtomicReference<>(0);
        objEventVO.getSubgoalIdList().stream().map(subgoalId -> {
            ResponseDTO<ObjectiveDIO> responseDTO = objectiveRemoteService.getObjective(subgoalId);
            return responseDTO.getData();
        }).filter(o -> {
            return Optional.of(o).isPresent();
        }).forEach(o -> {
           Integer subgoalId = o.getSubgoalId();
           ObjectiveQueryDIO query = new ObjectiveQueryDIO();
           query.setObjMasterType(ObjectiveMasterTypeConst.MASTERTYPE_PERSON);
           query.setParentObjId(subgoalId);
           query.setStatus(StatusEnum.ENABLE.getCode());
           //获取当年1月1日
           Date startDate = DateUtil.getYearStart(new DateTime(now).getYear());
           query.setStartDate(startDate);
           query.setEndDate(now);
           ResponseDTO<PageDRO<ObjectiveDIO>> responseDTO = objectiveRemoteService.listPageObjectiveByDIO(query);
           if(!responseDTO.isSuccess()) {
               return;
           }
           List<ObjectiveDIO> list = Optional.ofNullable(responseDTO.getData().getItemList()).orElse(new ArrayList<ObjectiveDIO>());
           if(list.isEmpty()){
               return;
           }
           String deptName = o.getDeptName();
           String objName = o.getObjName();
           Integer eventCode = getEventCode();
           Event event = Event.builder()
                   .eventName(StringUtils.join(deptName ,"-" ,objName))
                   .eventType(EventTypeEnum.OBJECTIVE.getTypeId())
                   .sceneId(objEventVO.getSceneId())
                   .relateId(subgoalId)
                   .status(StatusEnum.ENABLE.getCode())
                   .eventCode(eventCode)
                   .remarks(String.valueOf(new DateTime().getYear()))
                   .creater(objEventVO.getMcStaffName())
                   .updater(objEventVO.getMcStaffName())
                   .createTime(now)
                   .updateTime(now)
                   .build();
           flag.updateAndGet(v -> v + this.insert(event));

           ObjectiveEvent objectiveEvent = ObjectiveEvent.builder()
                   .eventId(event.getEventId())
                   .cubeMeasureId(o.getObjCubeId())
                   .subgoalId(o.getSubgoalId())
                   .eventCode(eventCode)
                   .creater(objEventVO.getMcStaffName())
                   .updater(objEventVO.getMcStaffName())
                   .createTime(now)
                   .updateTime(now)
                   .build();
           flag.updateAndGet(v -> v + objectiveEventDao.insert(objectiveEvent));

           //插入规则
           AlarmRule alarmRule = AlarmRule.builder()
                    .eventCode(eventCode)
                    .ruleName("绩效经营规则")
                    .droolsId(17)
                    .status(StatusEnum.ENABLE.getCode())
                    .creater(objEventVO.getMcStaffName())
                    .updater(objEventVO.getMcStaffName())
                    .createTime(now)
                    .updateTime(now)
                    .build();
            flag.updateAndGet(v -> v + alarmRuleDao.insert(alarmRule));

          //插入部门目标监控
          //list.add(o);
          list.stream().forEach(obj ->{

              ObjectiveRuleVO objectiveRuleVO = ObjectiveRuleVO.builder()
                      .objMasterType(obj.getObjMasterType())
                      .objMaster(obj.getObjMaster())
                      .objMasterName(obj.getObjMasterName())
                      .deptId(obj.getDeptId())
                      .deptName(obj.getDeptName())
                      .subgoalId(obj.getSubgoalId())
                      .list(this.getDefatultEarlyWarningConfig())
                      .build();

              //值域
              Threshold threshold = Threshold.builder()
                      .ruleId(alarmRule.getRuleId())
                      .thresholdName(String.format("[%s]绩效经营指标预警值", obj.getObjMasterName()))
                      .type(0)
                      .thresholdParam(String.valueOf(subgoalId))
                      .expression(ThresholdExpressionEnum.ALL.getExpression())
                      .thresholdValue(JSONObject.toJSONString(objectiveRuleVO))
                      .creater(objEventVO.getMcStaffName())
                      .updater(objEventVO.getMcStaffName())
                      .createTime(now)
                      .updateTime(now)
                      .build();
              flag.updateAndGet(v -> v + thresholdDao.insert(threshold));

            });
        });
        return flag.get();
    }

    /**
     * 随机生成事件编码
     * @return
     */
    public static Integer getEventCode(){
        Integer hashCodeV = UUID.randomUUID().toString().hashCode();
        if(hashCodeV < 0){//有可能是负数
            hashCodeV = - hashCodeV;
        }
        return hashCodeV;
    }

    /**
     * 设置默认预警值配置
     * @return
     */
    @Override
    public List<EarlyWarningConfig> getDefatultEarlyWarningConfig(){
        return setEarlyWarningConfig(100,100,95);
    }

    /**
     * 设置预警值配置
     * @return
     */
    @Override
    public List<EarlyWarningConfig> setEarlyWarningConfig(Integer value1,Integer value2,Integer value3){
        List<EarlyWarningConfig> expressionList = new ArrayList<>();
        EarlyWarningConfig config1 = new EarlyWarningConfig();
        config1.setKey(WronLevelEnum.ONE.getLevelId());
        config1.setValue(value1);
        config1.setExpression(ExpressionEnum.GTE.getExpression());
        expressionList.add(config1);

        EarlyWarningConfig config2 = new EarlyWarningConfig();
        config2.setKey(WronLevelEnum.TWO.getLevelId());
        config2.setValue(value2);
        config2.setExpression(ExpressionEnum.LT.getExpression());
        config2.setValue2(value3);
        config2.setExpression2(ExpressionEnum.GTE.getExpression());
        expressionList.add(config2);

        EarlyWarningConfig config3 = new EarlyWarningConfig();
        config3.setKey(WronLevelEnum.THREE.getLevelId());
        config3.setValue(value3);
        config3.setExpression(ExpressionEnum.LT.getExpression());
        expressionList.add(config3);
        return expressionList;
    }

    /**
     * 描述: 根据主键删除数据
     *
     * @param eventId 主键
     * @return 执行结果码
     * @author xujie
     * @since 2021-03-17 13:55:07
     */
    @Override
    public Integer deleteByKey(Integer eventId) {

        Assert.notNull(eventId, TAG + "参数 eventId 不能为空");
        return eventDao.deleteByKey(eventId);
    }

    /**
     * 描述: 根据主键批量删除数据
     *
     * @param eventIdList 待新增数据集合
     * @return java.lang.Integer 成功个数
     * @author xujie
     * @since  2021-03-17 13:55:07
     */
    @Override
    public Integer deleteBatchByKey(List<Integer> eventIdList) {

        if (eventIdList == null || eventIdList.size() == 0) {
            return null;
        }
        return eventDao.deleteBatchByKey(eventIdList);
    }


    /**
     * 根据事件ID获取事件状态
     * @param eventId
     * @return
     */
    @Override
    public Integer getStatusByEventId(Integer eventId){
        return eventDao.getStatusByEventId(eventId);
    }

}